//! 简易传输协议

#![no_std]
#![feature(const_btree_new)]

#[cfg(feature = "role_center")]
extern crate alloc;

mod address;
mod consts;
mod datagram;
mod history;
mod sender;
mod socket;

pub use address::Addr;
use consts::*;
pub use datagram::set_index;
use datagram::{Datagram, DatagramHeader};
use history::History;
use log::warn;
pub use socket::*;
use spin::Once;
use unmp::protocol::{Protocol, Respose};

static HISTORY: History = History::new();
static ETP: Once<Protocol> = Once::new();

/// 创建一个简易传输协议实例
pub fn init() {
    if let Ok(protocol) = Protocol::new(PROTOCOL_ID) {
        ETP.call_once(|| protocol);
        task_stream::spawn(async move {
            loop {
                let etp=ETP.get().unwrap();
                if let Some(rep) = etp.recv().await {
                    let Respose { data, conn } = rep;
                    let datagram = Datagram::parse(&data);
                    if let Ok(datagram) = datagram {
                        let head = datagram.head();
                        if head.control() < 0x80 {
                            // 响应
                            let mut is_repeat = false;
                            if head.control() & (1 << 1) == (1 << 1) {
                                // 需要去重
                                if !HISTORY.add(&datagram) {
                                    is_repeat = true;
                                }
                            }
                            if head.control() & (1 << 0) == (1 << 0) {
                                // 需要响应
                                let mut res = DatagramHeader::new(
                                    head.dstport(),
                                    head.srcport(),
                                    Some(head.index()),
                                );
                                res.set_control(0x81 | (is_repeat as u8) << 1);
                                let buf = res.generate(&[]);
                                let dst_conn = conn.clone();
                                task_stream::spawn(async move {
                                    let _err = etp.send( &buf, &dst_conn).await;
                                });
                            }
                            // 处理
                            if is_repeat {
                                return;
                            }
                            let addr = Addr::new(conn, head.srcport());
                            socket::when_recv(&datagram, addr)
                        } else {
                            // 收到响应
                            sender::finish(head.index()).await;
                        }
                    }
                } else {
                    warn!("etp recver exit.");
                    return;
                }
            }
        })
    } else {
        warn!("can't crate etp.")
    }
}
